﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;

public partial class Pages_Planner : System.Web.UI.Page
{
    Dictionary<StationPair, List<int>> busPlan = new Dictionary<StationPair, List<int>>(new StationPair.EqualityComparer());
    protected void Page_Load(object sender, EventArgs e)
    {
        ScriptManager.RegisterStartupScript(UpdatePanel1, UpdatePanel1.GetType(), "key", "crtaj();", true);
    }
    protected void btnSearch_Clicked(object sender, EventArgs e)
    {
        ViewState["lastTrigger"] = "search";
    }
    protected void btnClearAll_Clicked(object sender, EventArgs e)
    {
        ViewState["lastTrigger"] = "clear";
        string _scriptBuilder = string.Empty;
        lstStations.Items.Clear();
        _scriptBuilder += "clearAll();";
        lblEndStation.Text = "";
        lblStartStation.Text = "";
        lstBusses.DataSource = null;
        lstBusses.DataBind();
        ScriptManager.RegisterStartupScript(UpdatePanel1, UpdatePanel1.GetType(), "key3", _scriptBuilder, true);
    }
    protected void UpdatePanel1_Load(object sender, EventArgs e)
    {
       
    }
    public Dictionary<StationPair, List<int>> GetStationsNear(String[] _coords)
    {
        Dictionary<StationPair, List<int>> busPlanner = new Dictionary<StationPair, List<int>>();
        getStations stationsIds = new getStations();
        DataTable dtStations = stationsIds.Read();
        List<int> lstStationsIdsA = new List<int>();
        List<int> lstStationsIdsB = new List<int>();
        int rowsCount = dtStations.Rows.Count;
        //Check all stations to find those within 300 meters
        for (int i = 0; i < rowsCount; i++)
        {
            int _id = (int)dtStations.Rows[i]["StationID"];
            float latS = (float)dtStations.Rows[i]["SLatitude"];
            float lonS = (float)dtStations.Rows[i]["SLongitude"];
            string[] latlongA = _coords[0].Split('!');
            string[] latlongB = _coords[1].Split('!');
            double _distanceA = Utilities.Instance.distance(latS, lonS, double.Parse(latlongA[0]), double.Parse(latlongA[1]), 'K');
            double _distanceB = Utilities.Instance.distance(latS, lonS, double.Parse(latlongB[0]), double.Parse(latlongB[1]), 'K');
            if (_distanceA < 0.5 && _distanceA < _distanceB)
            {
                lstStationsIdsA.Add(_id);
            }
            if (_distanceB < 0.5 && _distanceB < _distanceA)
            {
                lstStationsIdsB.Add(_id);
            }
        }

        //Check for same bus that passes through both stations from starting and ending point
        for (int i = 0; i < lstStationsIdsA.Count; i++)
        {
            for (int j = 0; j < lstStationsIdsB.Count; j++)
            {
                getBusByStationId bussesIds = new getBusByStationId(lstStationsIdsA[i], lstStationsIdsB[j]);
                DataTable dtBusses = bussesIds.Read();
                int rowCountBusses = dtBusses.Rows.Count;
                List<int> busses = new List<int>();
                for (int k = 0; k < rowCountBusses; k++)
                {
                    busses.Add((int)dtBusses.Rows[k]["BusID"]);
                }
                if (busses.Count > 0)
                {
                    StationPair sp = new StationPair();
                    sp.stationA = lstStationsIdsA[i];
                    sp.stationB = lstStationsIdsB[j];
                    busPlanner.Add(sp, busses);
                }
            }
        }
        return busPlanner;
    }
    public List<StationDetails> GetDetailsForStations(StationPair sp, List<int> busses)
    {
        List<StationDetails> lstStationsDetails = new List<StationDetails>();
        Dictionary<int, Bus> busesInfo = new Dictionary<int, Bus>();
        for (int i = 0; i < busses.Count; i++)
        {
            getStationsByBusId busStations = new getStationsByBusId(busses[i]);
            double distance = 0;
            double distanceBetween = 0;
            double distanceToStartingStation = 0;
            double firstDistance = 0;
            int first = 0, second = 0; //used to determine the order in witch the stations are passed
            DataTable dtStationsForBus = busStations.Read();
            bool gotFirst = false;
            bool fromStarting = true;
            for (int j = 0; j < dtStationsForBus.Rows.Count - 1; j++)
            {
                if (sp.stationA == (int)dtStationsForBus.Rows[j]["StationID"]
                    || sp.stationB == (int)dtStationsForBus.Rows[j]["StationID"])
                {
                    gotFirst = true;
                }
                if (sp.stationA == (int)dtStationsForBus.Rows[j]["StationID"])
                {
                    first = j;
                }
                if (sp.stationB == (int)dtStationsForBus.Rows[j]["StationID"])
                {
                    second = j;
                }
                else if (sp.stationB == (int)dtStationsForBus.Rows[j + 1]["StationID"])
                {
                    second = j + 1;
                }
                distance += Utilities.Instance.distance((float)dtStationsForBus.Rows[j]["SLatitude"], (float)dtStationsForBus.Rows[j]["SLongitude"], (float)dtStationsForBus.Rows[j + 1]["SLatitude"], (float)dtStationsForBus.Rows[j + 1]["SLongitude"],'K');
                if (!gotFirst)
                {
                    firstDistance = distance;
                }
            }
            //calculate distance between start and end point
            if (first < second)
            {
                for (int j = first; j < second; j++)
                {
                    distanceBetween += Utilities.Instance.distance((float)dtStationsForBus.Rows[j]["SLatitude"], (float)dtStationsForBus.Rows[j]["SLongitude"], (float)dtStationsForBus.Rows[j + 1]["SLatitude"], (float)dtStationsForBus.Rows[j + 1]["SLongitude"], 'K');
                }
                distanceToStartingStation = firstDistance;
                fromStarting = true;
            }
            else
            {
                for (int j = first; j > second; j--)
                {
                    distanceBetween += Utilities.Instance.distance((float)dtStationsForBus.Rows[j]["SLatitude"], (float)dtStationsForBus.Rows[j]["SLongitude"], (float)dtStationsForBus.Rows[j - 1]["SLatitude"], (float)dtStationsForBus.Rows[j - 1]["SLongitude"],'K');
                }
                fromStarting = false;
                distanceToStartingStation = distance - distanceBetween - firstDistance;
            }
            //gather info for bus
            getBusById busDetails = new getBusById(busses[i]);
            DataRow trBus = busDetails.Read().Rows[0];
            if (!busesInfo.Keys.Contains(busses[i]))
            {
                Bus temp = new Bus((int)trBus["RoundTime"], Int32.Parse((string)trBus["BusNo"]), distance, trBus["StartTimes"].ToString(), trBus["EndTimes"].ToString(), trBus["StartTimesHoliday"].ToString(), trBus["EndTimesHoliday"].ToString(), trBus["StartTimesSunday"].ToString(), trBus["EndTimesSunday"].ToString());
                busesInfo.Add(busses[i], temp);
            }
            StationDetails sd = new StationDetails(sp, busesInfo[busses[i]], distanceBetween, distanceToStartingStation, fromStarting);

            //get arrival time
            if(DateTime.Now.DayOfWeek.Equals(DayOfWeek.Sunday)&&fromStarting){
                sd.StartTime = getArivalFromStartTime(busesInfo[busses[i]]._startTimesSunday, sd.TimeToFirstStation);
            }
            else if (DateTime.Now.DayOfWeek.Equals(DayOfWeek.Saturday) && fromStarting)
            {
                sd.StartTime = getArivalFromStartTime(busesInfo[busses[i]]._startTimesHoliday, sd.TimeToFirstStation);
            }
            else if (fromStarting)
            {
                sd.StartTime = getArivalFromStartTime(busesInfo[busses[i]]._startTimes, sd.TimeToFirstStation);
            }
            else if (DateTime.Now.DayOfWeek.Equals(DayOfWeek.Sunday) && !fromStarting)
            {
                sd.StartTime = getArivalFromStartTime(busesInfo[busses[i]]._endTimesSunday, sd.TimeToFirstStation);
            }
            else if (DateTime.Now.DayOfWeek.Equals(DayOfWeek.Saturday) && !fromStarting)
            {
                sd.StartTime = getArivalFromStartTime(busesInfo[busses[i]]._endTimesHoliday, sd.TimeToFirstStation);
            }
            else if (!fromStarting)
            {
                sd.StartTime = getArivalFromStartTime(busesInfo[busses[i]]._endTimes, sd.TimeToFirstStation);
            }
            lstStationsDetails.Add(sd);
        }
        return lstStationsDetails;
    }
    public String getArivalFromStartTime(string times,double timeFromStart)
    {
        string[] parts = times.Split(';');
        List<int> ret = new List<int>();
        for (int i = 0; i < parts.Length; i++)
        {
            int minutes = getMinutesFromString(parts[i]);
            int now = getMinutesFromString((DateTime.Now.Hour + ":" + DateTime.Now.Minute));
            int timeToStart = (int)Math.Ceiling(timeFromStart);
            if (minutes + timeToStart > now && minutes + timeToStart < now + 60)
            {
                ret.Add((int)Math.Ceiling(minutes + timeFromStart));
                //break;
            }
        }
        String s = "";
        if (ret.Count > 0)
        {       
            for (int i = 0; i < ret.Count; i++)
            {
                s += getStringFromMinutes(ret[i]);
                if (i != ret.Count - 1)
                {
                    s += ";";
                }
            }
        }
        else
        {
            s = "Нема следен автобус денес!";
        }
        return s;

    }

    private string getStringFromMinutes(int p)
    {
        int hour = p / 60;
        int minute = p % 60;
        string ret = String.Format("{0:00}:{1:00}", hour, minute);
        return ret;
    }

    private int getMinutesFromString(string p)
    {
        string[] parts = p.Split(':');
        int minutes = 0;
        minutes = Int32.Parse(parts[0]) * 60 + Int32.Parse(parts[1]);
        return minutes;
    }
    protected void lstStations_SelectedIndexChanged(object sender, EventArgs e)
    {
        ViewState["lastTrigger"] = "listbox";
        string _scriptBuilder = string.Empty;
        string[] ids = lstStations.SelectedItem.Value.Split('|');
        getStationForStationId stationA = new getStationForStationId(Int32.Parse(ids[0]));
        getStationForStationId stationB = new getStationForStationId(Int32.Parse(ids[1]));
        StationPair sp = new StationPair(Int32.Parse(ids[0]), Int32.Parse(ids[1]));
        lblStartStation.Text = stationA.Read().Rows[0]["Description"].ToString();
        lblEndStation.Text = stationB.Read().Rows[0]["Description"].ToString();
        if (ViewState["busPlan"] != null)
        {
            busPlan = new Dictionary<StationPair,List<int>>((Dictionary<StationPair, List<int>>)ViewState["busPlan"],new StationPair.EqualityComparer());
            List<StationDetails> sDetails = GetDetailsForStations(sp, busPlan[sp]);
            lstBusses.DataSource = sDetails;
            lstBusses.DataBind();
        }
       
        _scriptBuilder += "ShowMarkers(" + stationA.Read().Rows[0]["SLatitude"]+ "," + stationA.Read().Rows[0]["SLongitude"] + "," + stationB.Read().Rows[0]["SLatitude"]+ "," + stationB.Read().Rows[0]["SLongitude"]+");";
        ScriptManager.RegisterStartupScript(UpdatePanel1, UpdatePanel1.GetType(), "key4", _scriptBuilder, true);
    }
    protected void UpdatePanel1_PreRender(object sender, EventArgs e)
    {
        if (ViewState["lastTrigger"] != null)
        {
            if (ViewState["lastTrigger"].Equals("search"))
            {
                if (markerA.Value != "" && markerB.Value != "")
                {
                    string[] _coords = new string[2];
                    _coords[0] = markerA.Value;
                    _coords[1] = markerB.Value;

                    busPlan = GetStationsNear(_coords);
                    ViewState.Add("busPlan", busPlan);
                    lstStations.Items.Clear();
                    foreach (KeyValuePair<StationPair, List<int>> entry in busPlan)
                    {
                        getStationForStationId stationADetails = new getStationForStationId(entry.Key.stationA);
                        getStationForStationId stationBDetails = new getStationForStationId(entry.Key.stationB);
                        ListItem li = new ListItem();
                        li.Text = stationADetails.Read().Rows[0]["Description"] + " - " + stationBDetails.Read().Rows[0]["Description"];
                        li.Value = entry.Key.stationA + "|" + entry.Key.stationB;
                        lstStations.Items.Add(li);
                    }
                    lstStations.DataBind();
                    if (lstStations.Items.Count == 0)
                    {
                        btnClearAll_Clicked(sender, e);
                    }
                }
            }
        }
    }
}